﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Controls;
using KYKJ.Monitor.APIs;
using KYKJ.Monitor.PlayBack;

namespace KYKJ.Monitor.Video
{
    /// <summary>
    /// VideoMonitorControl.xaml 的交互逻辑
    /// </summary>
    public partial class VideoMonitorControl : UserControl
    {
        #region 字段

        private bool m_isStart;

        /// <summary>
        /// 图像的真实大小
        /// </summary>
        private System.Drawing.Size m_realBitmapSize;

        private int m_playSession;

        private bool m_isPlaying;

        private PlayAPIs m_player;

        private DecodeFrameDataDelegate decodeCallback;

        private TrackResultData m_trackResultData;

        private int m_centerX = 1280 / 2;

        private double m_widthRatio;

        private int m_centerY = 720 / 2;

        /// <summary>
        /// 偏移检测系数
        /// </summary>
        private int m_deviationCoefficient = 1;

        /// <summary>
        /// 允许的X范围
        /// </summary>
        private int m_xRange;

        /// <summary>
        /// 允许的X范围
        /// </summary>
        private int m_yRange;

        private BackgroundWorker m_worker = new BackgroundWorker();

        #endregion

        #region 属性

        public int TrackWidth { get; set; }

        public int TrackHeight { get; set; }

        /// <summary>
        /// 云台初始化状态
        /// </summary>
        public static int InitState { get; set; }

        #endregion

        #region 构造函数

        public VideoMonitorControl()
        {
            InitializeComponent();
            decodeCallback = DecodeFrameFinished;
            m_trackResultData = ReciveTrackResultData;
            this.CameraSet1.SetParent(this);
            TrackHeight = 50;
            TrackWidth = 50;

            m_worker.DoWork += M_worker_DoWork;

            m_player = new PlayAPIs();
            m_playSession = m_player.Init(this.PlayControl1.Handle,0);
        }

        #endregion

        #region 公开方法

        public void Close()
        {
            try
            {
                if (m_playSession < 0) return;
                if (m_isPlaying)
                {
                    m_isPlaying = false;
                    this.CameraSet1.Close();
                    m_player.Stop(m_playSession);
                }
                PTZControl.PtzRightEnd(1);
                PTZControl.Close();
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.StackTrace);
            }
        }

        #endregion

        #region 播放控件画框

        private void PlayControl1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            if (InitState == 0)
            {
                InitState = PTZControl.Init("192.168.0.66", 8877, "admin", "kykj123456", 1);
            }
            if (m_playSession < 0) return;
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                m_isStart = true;
            }
        }

        private void PlayControl1_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            m_widthRatio = 1280 * 1.0 / PlayControl1.Width;
            if (m_playSession < 0) return;
            if (m_isStart == false) return;
            m_isStart = false;

            System.Drawing.Graphics g = PlayControl1.CreateGraphics();
            System.Drawing.Rectangle rct = new System.Drawing.Rectangle();
            rct.X = e.X - this.TrackWidth / 2;
            rct.Y = e.Y - this.TrackHeight / 2;
            rct.Width = this.TrackWidth;
            rct.Height = this.TrackHeight;
            g.DrawRectangle(new System.Drawing.Pen(System.Drawing.Color.Red, 1), rct);
            g.Dispose();

            if (this.m_realBitmapSize.Width < 1 || this.m_realBitmapSize.Height < 1) return;
            int x = this.PlayControl1.Width - e.X - this.TrackWidth / 2;
            int y = this.PlayControl1.Height -e.Y - this.TrackHeight / 2;
            x = x > 0 ? x : 0;
            y = y > 0 ? y : 0;
            int width = this.TrackWidth, height = this.TrackHeight;
            double xzoom = this.PlayControl1.Width * 1.0 / this.m_realBitmapSize.Width;
            double yzoom = this.PlayControl1.Height * 1.0 / this.m_realBitmapSize.Height;
            x = (int)(x / xzoom);
            width = (int)(width / xzoom);
            m_xRange = width;
            y = (int)(y / yzoom);
            height = (int)(height / yzoom);
            m_yRange = height;
            x = x + width < this.m_realBitmapSize.Width ? x : this.m_realBitmapSize.Width - width - 3;
            y = y + height < this.m_realBitmapSize.Height ? y : this.m_realBitmapSize.Height - height - 3;
            m_player.SetTrackRectangle(m_playSession, x, y, width, height, m_trackResultData);
        }

        private void UserControl_Loaded(object sender, System.Windows.RoutedEventArgs e)
        {
            if (m_playSession < 0) return;
            if (!m_isPlaying)
            {
                m_isPlaying = true;
                m_player.Play(m_playSession, "rtsp://admin:kykj123456@192.168.0.66/h264/ch1/main/av_stream", decodeCallback);
                //m_playerInfrared.Play(m_playInfraredSession, "rtsp://admin:kykj123456@192.168.0.66/h264/ch1/sub/av_stream", decodeInfraredCallback);
            }
        }

        private int DecodeFrameFinished(IntPtr frameData, int size)
        {
            byte[] data = new byte[size];
            Marshal.Copy(frameData, data, 0, size);
            MemoryStream ms = new MemoryStream(data);
            System.Drawing.Image bitImg = (System.Drawing.Image)System.Drawing.Image.FromStream(ms).Clone();
            bitImg.RotateFlip(RotateFlipType.Rotate180FlipNone);
            //img.RotateFlip(RotateFlipType.Rotate90FlipNone);
            //顺时针旋转90度 RotateFlipType.Rotate90FlipNone
            //逆时针旋转90度 RotateFlipType.Rotate270FlipNone
            //水平翻转 RotateFlipType.Rotate180FlipY
            //垂直翻转 RotateFlipType.Rotate180FlipX

            ms.Close();
            this.m_realBitmapSize.Width = bitImg.Width;
            this.m_realBitmapSize.Height = bitImg.Height;
            this.Dispatcher.BeginInvoke(new Action(() =>
            {
                this.PlayControl1.Image = bitImg;
                //PlayControl1.Refresh();
            }));
            return 0;
        }

        private int ReciveTrackResultData(IntPtr imageData, int size, int width, int height, int step, int trackX, int trackY, int trackW, int trackH)
        {
            try
            {
                Bitmap bitmap = (Bitmap) ConvertMatToBitmap(imageData, 0, 3, width, height, step).Clone();
                Bitmap bitImg = new Bitmap(bitmap);
                bitImg.RotateFlip(RotateFlipType.Rotate180FlipNone);
                this.Dispatcher.BeginInvoke(new Action(() =>
                {
                    this.PlayControl1.Image = bitImg;
                    //PlayControl1.Refresh();
                }));
                return 0;
                if (trackX < 0)
                {
                    return 0;
                }
                if (InitState <= -1) return 0; //如果云台没有权限则直接返回
                if (m_worker.IsBusy) return 0;
                TrackInfo info = new TrackInfo(trackX, trackY, trackW, trackH);
                m_worker.RunWorkerAsync(info);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.StackTrace);
            }
            return 0;
        }

        private void M_worker_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                TrackInfo info = e.Argument as TrackInfo;
                int xDisparity = info.TrackX - m_centerX; //目标中心和图像中心的差距
                int yDisparity = info.TrackY - m_centerY; //目标中心和图像中心的差距
                uint speed = 1;

                #region x和Y方向都有变化

                if (Math.Abs(xDisparity) > m_deviationCoefficient*this.TrackWidth &&
                    Math.Abs(yDisparity) > m_deviationCoefficient*this.TrackHeight)
                {
                    PTZControl.PtzRightEnd(1);

                    uint xSpeed = 3;
                    //if (xDisparity > 1096)
                    //{
                    //    xSpeed = 7;
                    //}
                    //else if (xDisparity > 914)
                    //{
                    //    xSpeed = 6;
                    //}
                    //else if (xDisparity > 731)
                    //{
                    //    xSpeed = 5;
                    //}
                    //else if (xDisparity > 548)
                    //{
                    //    xSpeed = 4;
                    //}
                    //else 
                    if (xDisparity > 365)
                    {
                        xSpeed = 3;
                    }
                    else if (xDisparity > 182)
                    {
                        xSpeed = 2;
                    }
                    //else
                    //{
                    //    xSpeed = 1;
                    //}
                    uint ySpeed = 3;
                    //if (yDisparity > 617)
                    //{
                    //    ySpeed = 7;
                    //}
                    //else if (yDisparity > 510)
                    //{
                    //    ySpeed = 6;
                    //}
                    //else if (yDisparity > 408)
                    //{
                    //    ySpeed = 5;
                    //}
                    //else if (yDisparity > 306)
                    //{
                    //    ySpeed = 4;
                    //}
                    //else 
                    if (yDisparity > 204)
                    {
                        ySpeed = 3;
                    }
                    else if (yDisparity > 102)
                    {
                        ySpeed = 2;
                    }
                    //else
                    //{
                    //    ySpeed = 1;
                    //}
                    //speed = Math.Min(xSpeed,ySpeed);//取较小的速度
                    //speed = Math.Max(xSpeed, ySpeed);//取较小的速度
                    speed = (xSpeed+ySpeed)/2;//取较小的速度
                    //开始设置云台转动方向
                    if (xDisparity > 0)
                    {
                        if (yDisparity > 0)
                        {
                            PTZControl.PtzRightDownStart(speed);
                        }
                        else
                        {
                            PTZControl.PtzRightUpStart(speed);
                        }
                    }
                    else
                    {
                        if (yDisparity > 0)
                        {
                            PTZControl.PtzLeftDownStart(speed);
                        }
                        else
                        {
                            PTZControl.PtzLeftUpStart(speed);
                        }
                        PTZControl.PtzLeftStart(speed);
                    }
                    return;
                }

                #endregion

                #region 只有X方向变化

                if (Math.Abs(xDisparity) > m_deviationCoefficient * this.TrackWidth && Math.Abs(yDisparity) < m_deviationCoefficient * this.TrackHeight) 
                    //m_xRange) //xDisparity差距大于预置阀值，则开始转动镜头
                {
                    PTZControl.PtzRightEnd(1);
                    if (xDisparity > 1096)
                    {
                        speed = 7;
                    }
                    else if (xDisparity > 914)
                    {
                        speed = 6;
                    }
                    else if (xDisparity > 731)
                    {
                        speed = 5;
                    }
                    else if (xDisparity > 548)
                    {
                        speed = 4;
                    }
                    else if (xDisparity > 365)
                    {
                        speed = 3;
                    }
                    else if (xDisparity > 182)
                    {
                        speed = 2;
                    }
                    else
                    {
                        speed = 1;
                    }
                    //开始设置云台转动方向
                    if (xDisparity > 0)
                    {
                        PTZControl.PtzRightStart(speed);
                    }
                    else
                    {
                        PTZControl.PtzLeftStart(speed);
                    }
                    return;
                }

                #endregion

                #region 只有Y方向变化

                if (Math.Abs(yDisparity) > m_deviationCoefficient*this.TrackHeight && Math.Abs(xDisparity) < m_deviationCoefficient * this.TrackWidth)
                    //m_xRange) //xDisparity差距大于预置阀值，则开始转动镜头
                {
                    PTZControl.PtzRightEnd(1);
                    if (yDisparity > 617)
                    {
                        speed = 7;
                    }
                    else if (yDisparity > 510)
                    {
                        speed = 6;
                    }
                    else if (yDisparity > 408)
                    {
                        speed = 5;
                    }
                    else if (yDisparity > 306)
                    {
                        speed = 4;
                    }
                    else if (yDisparity > 204)
                    {
                        speed = 3;
                    }
                    else if (yDisparity > 102)
                    {
                        speed = 2;
                    }
                    else
                    {
                        speed = 1;
                    }
                    //开始设置云台转动方向
                    if (yDisparity > 0)
                    {
                        PTZControl.PtzDownStart(speed);
                    }
                    else
                    {
                        PTZControl.PtzUpStart(speed);
                    }
                }
                #endregion
                else
                {
                    //if (m_ptzState == 0)
                    //{
                    //    PTZControl.PtzLeftEnd(2);
                    //}
                    //else
                    //{
                    //    PTZControl.PtzRightEnd(2);
                    //}
                    PTZControl.PtzRightEnd(1);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.StackTrace);
            }
        }

        #endregion

        #region 私有方法

        private Bitmap ConvertMatToBitmap(IntPtr imageData, int depth, int channels, int cols, int rows, int step, int cv8UType = 0)
        {
            System.Drawing.Bitmap bmpImg = null;
            //检查图像位深  
            if (depth != cv8UType)
            {
                bmpImg = new Bitmap(1, 1, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
                return (bmpImg);
            }
            //彩色图像  
            if (channels == 3)
            {
                bmpImg = new Bitmap(
                    cols,
                    rows,
                    step,
                    System.Drawing.Imaging.PixelFormat.Format24bppRgb,
                    imageData);
            }
            else if (channels == 4)
            {
                bmpImg = new Bitmap(
                    cols,
                    rows,
                    step,
                    System.Drawing.Imaging.PixelFormat.Format32bppArgb,
                    imageData);
            }
            //灰度图像  
            else if (channels == 1)
            {
                bmpImg = new Bitmap(
                    cols,
                    rows,
                    step,
                    System.Drawing.Imaging.PixelFormat.Format8bppIndexed,
                    imageData);
            }
            return bmpImg;
        }

        #endregion
    }
}
